home *** CD-ROM | disk | FTP | other *** search
- /* */
- /*** symmetry.c - Nina Amenta, Aug. 1989 ****/
- /* */
- #include <math.h>
- #include <stdio.h>
- #include <gl.h>
- #include "symmetry.h"
-
- LINE *AddLineToObject();
- LINE *AllRotations();
- LINE *MakeCurrentObject();
- LINE *ReadPattern();
- LINE *ReadLine();
- POINT ORIGIN = {0.0,0.0};
- LINE *NewLine();
- void PickLine();
- float distance();
-
- /* symmetry =
- admissible transformations
- translation vector1 (screen basis)
- translation vector2 (screen basis)
- #reflections
- reflection vectors (standard basis)
- glide reflection flag
- #rotations
-
- note: the SCREEN basis is the lattice as displayed, ie under user control.
- Internally, things assume the STANDARD {1,0},{0,1} basis for the lattice.
-
- */
- SYMMETRY SYMTAB[NUM_SYM] = {
- {0,{60.0,-103.923},{60.0,103.923},0,
- {{0.0,0.0},{0.0,0.0}},0,3,"p3 - 3-way rotation"},
- {ANG | RAT,{100.0,0.0},{0.0,100.0},0,
- {{0.0,0.0},{0.0,0.0}},0,2,"p2 - 2 way rotation"},
- {ANG | RAT,{100.0,-100.0},{100.0,100.0},0,
- {{0.0,0.0},{0.0,0.0}},0,0,"p1 - translation"},
- {RAT,{100.0,0.0},{0.0,100.0},1,
- {{0.0,0.5},{0.0,0.0}},GLIDE,0,"pg - 1 glide reflection"},
- {RAT,{125.0,0.0},{0.0,125.0},2,
- {{0.5,0.0},{0.0,0.5}},GLIDE,0,"pgg - 2 glide reflections"},
- {RAT,{125.0,0.0},{0.0,125.0},1,
- {{0.0,0.5},{0.0,0.0}},GLIDE,2,"pmg - glide reflection w/ 2-way rotation"},
- {RAT,{125.0,0.0},{0.0,125.0},1,
- {{0.0,0.5},{0.0,0.0}},0,0,"pm - 1 lattice reflection"},
- {ANG,{60.0,-103.923},{60.0,103.923},1,
- {{0.5,0.5},{0.0,0.0}},0,0,"cm - 1 off-lattice reflection"},
- {RAT,{125.0,0.0},{0.0,125.0},1,
- {{0.0,0.5},{0.0,0.0}},0,2,"pmm - 2 lattice reflections"},
- {ANG,{100.0,-100.0},{100.0,100.0},1,
- {{0.5,0.5},{0.0,0.0}},0,2,"cmm - 2 off-lattice reflections"},
- {0,{90.0,-155.884},{90.0,155.884},1,
- {{0.0,0.5},{0.0,0.0}},0,3,"p31m - 3 lattice reflections"},
- {0,{90.0,-155.884},{90.0,155.884},1,
- {{1.0,2.0},{0.0,0.0}},0,3,"p3m1 - 3 off-lattice reflections"},
- {0,{100.0,-100.0},{100.0,100.0},0,
- {{0.0,0.0},{0.0,0.0}},0,4,"p4 - 4-way rotation"},
- {0,{100.0,-100.0},{100.0,100.0},1,
- {{0.5,0.5},{0.0,0.0}},GLIDE,4,"p4g - glide reflection w/ 4-way rotation"},
- {0,{100.0,-100.0},{100.0,100.0},1,
- {{0.5,0.5},{0.0,0.0}},0,4,"p4m - reflection w/ 4-way rotation"},
- {0,{90.0,-155.884},{90.0,155.884},0,
- {{0.0,0.0},{0.0,0.0}},0,6,"p6 - 6-way rotation"},
- {0,{90.0,-155.884},{90.0,155.884},1,
- {{0.0,0.5},{0.0,0.0}},0,6,"p6m - reflection w/ 6-way rotation"}
- };
-
-
- DefineSymWindow(s_rect,sym,w_rect,scale)
- RECTANGLE *w_rect,*s_rect;
- SYMMETRY *sym;
- float scale;
- {
- float x,y;
- VECTOR vec1,vec2;
- extern WINDOW win;
-
- RearrangeVectors(&(sym->v1),&(sym->v2),&vec1,&vec2);
- x = vec1.x + vec2.x;
- y = vec2.y - vec1.y;
- s_rect->width = ((int)(scale*w_rect->width/x) + 1) * x;
- s_rect->height = ((int)(scale*w_rect->height/y) + 1) * y;
- winset(win);
- ortho2(0.0,scale*w_rect->width,0.0,scale*w_rect->height);
- }
-
-
- int SetUpSymmetry(s,pointpointer,xforms,s_rec)
- SYMMETRY *s;
- POINT **pointpointer;
- XFORM xforms[];
- RECTANGLE *s_rec;
- {
- int i=0; int j;
- VECTOR vec1,vec2;
- RECTANGLE virtual;
- POINT *pts;
- int maxpts;
-
- virtual.x = virtual.y = 0;
- virtual.width = s_rec->width;
- virtual.height = s_rec->height;
-
- if (*pointpointer != NULL) free(*pointpointer);
- RearrangeVectors(&(s->v1),&(s->v2),&vec1,&vec2);
- maxpts = 2 * (s_rec->width/(vec1.x+vec2.x) + 1) *
- (s_rec->height/(vec2.y-vec1.y) + 1); /* plus 1 for good luck */
- pts = (POINT *)malloc(maxpts*sizeof(POINT));
- *pointpointer = pts;
- pts[0].x = 0.0; pts[0].y = 0.0;
-
- /* lay down points of symmetry */
- for (;;)
- {
- j = i; /* begining of this last row */
- while (RectIncludesPoint(virtual,pts[i]))
- {
- bump(pts+i,pts+i+1,1,&vec1);
- i++;
- }
- bump(pts+j,pts+i,1,&vec2);
- if (PointRightOfRect(pts[i],virtual)) break;
- while (RectIncludesPoint(virtual,pts[i]))
- bump(pts+i,pts+i,-1,&vec1);
- while (!RectIncludesPoint(virtual,pts[i])) {
- bump(pts+i,pts+i,1,&vec1);
- if (PointRightOfRect(pts[i],virtual)) break;
- }
- }
- SetUpParameterization(&(s->v1),&(s->v2),xforms[3],xforms[4]);
- if (s->rot>1)
- SetUpRot(2.0*M_PI/(s->rot),xforms[0]);
- if (s->refl!=0)
- for (j=0; j<s->refl; j++)
- SetUpRefl(&(s->reflections[j]),xforms[j+1],xforms[3]);
- return(i);
- }
-
- RearrangeVectors(in1,in2,vec1,vec2)
- VECTOR *in1,*in2,*vec1,*vec2;
- {
- VECTOR tmp;
- CopyVector(in1,vec1);
- CopyVector(in2,vec2);
- if (vec2->x < 0.0) VectorScalarMult(vec2,-1.0);
- if (vec1->x < 0.0) VectorScalarMult(vec1,-1.0);
- if ((vec1->y > 0.0) && (vec2->y < 0.0)) {
- CopyVector(vec1,&tmp); CopyVector(vec2,vec1); CopyVector(&tmp,vec2);
- }
- while ((vec1->y > 0.0) || (vec2->y < 0.0)) {
- vec2->x = vec1->x - vec2->x;
- vec2->y = vec1->y - vec2->y;
- if (vec2->x < 0.0) VectorScalarMult(vec2,-1.0);
- if ((vec1->y > 0.0) && (vec2->y < 0.0)) {
- CopyVector(vec1,&tmp); CopyVector(vec2,vec1); CopyVector(&tmp,vec2);
- }
- }
- }
-
- SetUpParameterization(vec1,vec2,std2scr,scr2std)
- VECTOR *vec1,*vec2;
- XFORM std2scr,scr2std;
- {
- std2scr[0] = vec1->x;
- std2scr[1] = vec1->y;
- std2scr[2] = vec2->x;
- std2scr[3] = vec2->y;
- InvertMatrix(std2scr,scr2std);
- }
-
-
- SetUpRefl(v,xform,std2scr)
- VECTOR *v;
- XFORM xform,std2scr;
- {
- XFORM temp;
- double angle;
- VECTOR w;
-
- /* reflection vector is in standard basis, convert to screen basis */
- VectorMatrixMult(v,std2scr,&w);
- angle=atan2((double)w.y,(double)w.x);
- /* reflection across the x axis */
- temp[0] = 1;
- temp[1] = temp[2] = 0;
- temp[3] = -1;
- /* rotate to x axis */
- SetUpRot(-angle,xform);
- /* reflect */
- MatrixMultiply(xform,temp,temp);
- /* rotate back */
- SetUpRot(angle,xform);
- MatrixMultiply(temp,xform,xform);
- }
-
- SetUpRot(angle,xform)
- double angle;
- float *xform;
- {
- xform[1] = sin(angle);
- xform[2] = -sin(angle);
- xform[0] = xform[3] = cos(angle);
- }
-
- DrawPoints(pts,cnt)
- POINT *pts;
- int cnt;
- {
- int i;
- for (i=0; i<cnt; i++)
- DrawDot(&pts[i]);
- }
-
-
-
- LINE *MakeCurrentObject(Lines,sym,xforms,bounds)
- LINE *Lines;
- SYMMETRY *sym;
- XFORM xforms[];
- RECTANGLE *bounds;
- {
- int i,j,pos_count;
- LINE cur,temp,*line_ptr,*obj;
- VECTOR glide[2];
-
- obj = NULL;
- bounds->x = bounds->y = bounds->width = bounds->height = 0.0;
- /* transform glide reflection vectors from standard to current basis */
- if (sym->glide == GLIDE) {
- VectorMatrixMult(&(sym->reflections[0]),xforms[3],&(glide[0]));
- VectorMatrixMult(&(sym->reflections[1]),xforms[3],&(glide[1]));
- }
- else {
- glide[0].x = glide[1].x = glide[0].y = glide[0].y = 0.0;
- }
-
- for (line_ptr=Lines; line_ptr != NULL; line_ptr = line_ptr->next)
- {
- CopyLine(line_ptr,&cur);
- /* Convert from standard basis to screen coordinate basis */
- MatrixMultiply(cur.m,xforms[3],cur.m);
- pos_count = 0; /* used in picking */
- obj = AllRotations(&cur,xforms[0],sym,obj,bounds,&pos_count);
- if (sym->refl > 0)
- {
- for (i=1; i<=sym->refl; i++)
- {
- temp.id = cur.id;
- MatrixMultiply(cur.m,xforms[i],temp.m);
- TranslateLine(&temp,&(glide[i-1]),1,&temp);
- obj = AllRotations(&temp,xforms[0],sym,obj,bounds,&pos_count);
- if (i==2)
- {
- MatrixMultiply(temp.m,xforms[1],temp.m);
- TranslateLine(&temp,&(glide[0]),1,&temp);
- obj = AllRotations(&temp,xforms[0],sym,obj,bounds,&pos_count);
- }
-
- }
- }
- }
- return(obj);
- }
-
- FreeObject(obj)
- LINE *obj;
- {
- LINE *cur;
- while (obj != NULL)
- {
- cur = obj;
- obj = obj->next;
- free(cur);
- }
- }
-
-
- LINE *AllRotations(l,xform,sym,obj,bounds,pos_count)
- LINE *l,*obj;
- MATRIX xform;
- SYMMETRY *sym;
- RECTANGLE *bounds;
- int *pos_count;
- {
- int j;
- LINE temp;
-
- CopyLine(l,&temp);
- obj = AddLineToObject(obj,&temp,bounds,pos_count);
- for (j=1; j<sym->rot; j++)
- {
- MatrixMultiply(temp.m,xform,temp.m);
- obj = AddLineToObject(obj,&temp,bounds,pos_count);
- }
- return(obj);
- }
-
- LINE *AddLineToObject(obj,l,r,pos_count)
- LINE *obj,*l;
- RECTANGLE *r;
- int *pos_count;
- {
- LINE *new;
- new = NewLine(obj);
- new->obj_pos = (*pos_count)++;
- CopyLine(l,new);
- AdjustBoundingBox(new,r);
- return(new);
- }
-
- AdjustBoundingBox(l,r)
- LINE *l;
- RECTANGLE *r;
- {
- float min,max;
- GetMinMax(r->x,r->width,l->m[EX],l->m[SX],&min,&max);
- r->x = min;
- r->width = max;
- GetMinMax(r->y,r->height,l->m[EY],l->m[SY],&min,&max);
- r->y = min;
- r->height = max;
- }
-
- GetMinMax(a,b,c,d,min,max)
- float a,b,c,d,*min,*max;
- {
- float tmp;
-
- if (b < a) { tmp=a; a=b; b=tmp;}
- if (c < a) { tmp=a; a=c; c=tmp;}
- if (d < a) { tmp=a; a=d; d=tmp;}
- if (b > d) { tmp=b; b=d; d=tmp;}
- if (c > d) { tmp=c; c=d; d=tmp;}
- *min = a;
- *max = d;
- }
-
- /* Translate the design to each of the centers of symmetry on the screen,
- and draw it. Call ReplicateOffEdges to draw the pieces of designs around
- the edges of the picture that belong to centers of symmetry that are just
- off the screen. */
- ReplicateObject(rect,obj,pts,count,bounds,vec1,vec2,drawing_routine)
- RECTANGLE *rect;
- LINE *obj;
- POINT *pts;
- int count;
- RECTANGLE *bounds;
- VECTOR *vec1,*vec2;
- void (*drawing_routine) ();
- {
- int i;
-
- for (i=0; i<count; i++)
- {
- /* For picking */
- if (drawing_routine == PickLine)
- LogTranslation(i);
- TranslateCoordinates(pts[i].x,pts[i].y,0.0);
- DrawObject(obj,drawing_routine);
- ReplicateOffEdges
- (rect,obj,&pts[i],bounds,vec1,vec2,drawing_routine);
-
- TranslateBack();
- }
- }
-
- /* Rearranges the line so the closest endpoint to the point
- is EX,EY */
-
- ClosestEndpoint(line,p)
- LINE *line;
- POINT * p;
- {
- float temp;
- temp = distance(line->m[EX],line->m[EY],p->x,p->y);
- temp = distance(line->m[SX],line->m[SY],p->x,p->y);
- if (distance(line->m[EX],line->m[EY],p->x,p->y) >
- distance(line->m[SX],line->m[SY],p->x,p->y))
-
- {
- temp = line->m[SX]; line->m[SX] = line->m[EX]; line->m[EX] = temp;
- temp = line->m[SY]; line->m[SY] = line->m[EY]; line->m[EY] = temp;
- }
- }
-
- float distance(qx,qy,px,py)
- float qx,qy,px,py;
- {
- float temp;
- temp = sqrt((qx-px)*(qx-px) + (qy-py)*(qy-py));
- return(temp);
- }
-
- /* Look at all adjacent possible centers of symmetry in the lattice.
- If any of these are off the screen, but the current bounding box of
- the design intersects the screen, draw the design at that center.
- Then try another step in the same direction. */
-
- ReplicateOffEdges(screen,obj,p,bounds,vec1,vec2,drawing_routine)
- RECTANGLE *screen;
- LINE *obj;
- POINT *p;
- RECTANGLE *bounds;
- VECTOR *vec1,*vec2;
- void (*drawing_routine) ();
- {
- VECTOR v;
-
- DrawIfNecessary(screen,obj,p,bounds,vec1,1,vec1,vec2,drawing_routine);
- DrawIfNecessary(screen,obj,p,bounds,vec2,1,vec1,vec2,drawing_routine);
- DrawIfNecessary(screen,obj,p,bounds,vec1,-1,vec1,vec2,drawing_routine);
- DrawIfNecessary(screen,obj,p,bounds,vec2,-1,vec1,vec2,drawing_routine);
- AddVector(vec1,vec2,1,&v);
- DrawIfNecessary(screen,obj,p,bounds,&v,1,vec1,vec2,drawing_routine);
- DrawIfNecessary(screen,obj,p,bounds,&v,-1,vec1,vec2,drawing_routine);
- AddVector(vec1,vec2,-1,&v);
- DrawIfNecessary(screen,obj,p,bounds,&v,1,vec1,vec2,drawing_routine);
- DrawIfNecessary(screen,obj,p,bounds,&v,-1,vec1,vec2,drawing_routine);
- }
-
- DrawIfNecessary(screen,obj,p,bounds,vec,direction,vec1,vec2,drawing_routine)
- RECTANGLE *screen;
- LINE *obj;
- POINT *p;
- RECTANGLE *bounds;
- VECTOR *vec,*vec1,*vec2;
- int direction;
- void (*drawing_routine) ();
- {
- POINT q;
- bump(p,&q,direction,vec);
- if (!RectIncludesPoint(*screen,q) &&
- BBoxIntersectsRect(&q,bounds,screen))
- {
- TranslateCoordinates(direction*vec->x,direction*vec->y,0.0);
- DrawObject(obj,drawing_routine);
- DrawIfNecessary(screen,obj,&q,bounds,vec,direction,
- vec1,vec2,drawing_routine);
- TranslateBack();
- }
- }
-
-
- int BBoxIntersectsRect(p,bounds,screen)
- POINT *p;
- RECTANGLE *bounds;
- RECTANGLE *screen;
- {
- if (((p->x+bounds->width > screen->x) &&
- (p->x+bounds->x < screen->x+screen->width)) &&
- ((p->y+bounds->height > screen->y) &&
- (p->y+bounds->y < screen->y+screen->height))) return(TRUE);
- return(FALSE);
- }
-
- TranslateLine(s,v,scale,d)
- LINE *s,*d;
- VECTOR *v;
- int scale;
- {
- MATRIX temp;
-
- temp[0] = s->m[0]+scale*v->x;
- temp[1] = s->m[1]+scale*v->y;
- temp[2] = s->m[2]+scale*v->x;
- temp[3] = s->m[3]+scale*v->y;
- CopyMatrix(temp,d->m);
- d->id = s->id;
- }
-
-
- CopyMatrix(f,t)
- MATRIX f,t;
- {
- int i;
- for (i=0;i<4;i++) t[i]=f[i];
- }
-
- CopyLine(f,t)
- LINE *f,*t;
- {
- CopyMatrix(f->m,t->m);
- t->id = f->id;
- }
-
- CopyVector(v,w)
- VECTOR *v,*w;
- {
- w->x = v->x; w->y = v->y;
- }
-
- CopyRectangle(f,t)
- RECTANGLE *f,*t;
- {
- t->x = f->x; t->y = f->y;
- t->width = f->width; t->height = f->height;
- }
-
- AddVector(v,w,scale,d)
- VECTOR *v,*w,*d;
- int scale;
- {
- d->x = v->x + scale*w->x;
- d->y = v->y + scale*w->y;
- }
-
- MatrixMultiply(s,t,d)
- MATRIX s,t,d;
- {
- MATRIX temp;
- int i;
- temp[0] = s[0]*t[0]+s[1]*t[2];
- temp[1] = s[0]*t[1]+s[1]*t[3];
- temp[2] = s[2]*t[0]+s[3]*t[2];
- temp[3] = s[2]*t[1]+s[3]*t[3];
- CopyMatrix(temp,d);
- }
-
- VectorMatrixMult(s,m,d)
- VECTOR *s,*d;
- MATRIX m;
- {
- VECTOR temp;
- temp.x = s->x*m[0]+s->y*m[2];
- temp.y = s->x*m[1]+s->y*m[3];
- d->x = temp.x; d->y = temp.y;
- }
-
- VectorScalarMult(v,f)
- VECTOR *v;
- float f;
- {
- v->x *= f; v->y *= f;
- }
-
- InvertMatrix(s,d)
- MATRIX s,d;
- {
- float det;
- det = s[0]*s[3] - s[1]*s[2];
- d[0] = s[3]/det;
- d[1] = -s[1]/det;
- d[2] = -s[2]/det;
- d[3] = s[0]/det;
- }
-
-
- NewId(line)
- LINE *line;
- {
- static short newid=0;
- line->id = newid++;
- }
-
- LINE *NewLine(Lines)
- LINE *Lines;
- {
- LINE *new;
- new = (LINE*) malloc(sizeof(LINE));
- new->next = Lines;
- return(new);
- }
-
-
- LINE *ReadPattern(Lines,pat)
- LINE *Lines;
- FILE *pat;
- {
- LINE *cur;
- int id=0;
-
- for (cur=ReadLine(pat); cur!=NULL; cur=ReadLine(pat))
- {
- cur->next = Lines;
- cur->id = id++;
- Lines = cur;
- }
- return(Lines);
- }
-
-
- LINE *ReadLine(pat)
- FILE *pat;
- {
- LINE *l;
- l = NewLine(NULL);
- if (fscanf(pat,"%f %f %f %f",&l->m[0],&l->m[1],&l->m[2],&l->m[3])!=EOF)
- return (l);
- else
- {
- free(l);
- return(NULL);
- }
- }
-
-
-
-
-
-
-
-
-